//
// Created by ca on 2022/8/18.
//

#include "data_record.h"
#include "public_define.h"

#include "dat_parser.h"
#include "common_opr_all.h"
#include "dc_util.h"
#include "tool.h"

int32_t DataRecord::m_eventPrefixLenPos = 17;

set<string> VedioColSet = {
    ENCODE_SRV_H265_CAM0,
    ENCODE_SRV_H265_CAM1,
    ENCODE_SRV_H265_CAM2,
    ENCODE_SRV_H265_CAM3,
    ENCODE_SRV_H265_CAM4,
    ENCODE_SRV_H265_CAM5,
    ENCODE_SRV_H265_CAM6,
    ENCODE_SRV_H265_CAM7,
    ENCODE_SRV_H265_CAM8,
    ENCODE_SRV_H265_CAM9,
    ENCODE_SRV_H265_CAM10
};

set<string> PicColSet = {
    "encode_srv-EncodeSrv.EncodeJpeg-CAM0",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM1",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM2",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM3",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM4",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM5",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM6",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM7",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM8",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM9",
    "encode_srv-EncodeSrv.EncodeJpeg-CAM10"
};


DataRecord::DataRecord()
{
}

DataRecord::~DataRecord()
{
    if (spRecord)
    {
        Log_Info("Close file: {}", m_fileName);
        spRecord->Close();
    }

    struct stat s_buf;
    int retCI = stat(m_fileName.c_str(), &s_buf);
    (void)retCI;   
    Log_Info("write file end filename: {}  {} MB", m_fileName, to_string((double)s_buf.st_size/1024/1024));
}

std::string DataRecord::initializeRecord(const std::string &tuominFileWithPath)
{
    //init文件获取一次系统时间，作为基础时间
    //m_firstFrameUTCtime = getDoubleTime();
    m_TriggerUTCtime =getDoubleTime();
    m_TriggerStartTime =KTime::getPubTime();
    std::string fileName = tuominFileWithPath;
    //初始化记录文件
    spRecord = std::make_shared<CRecord>(fileName);
    spRecord->Init();
    m_fileName = fileName;
    Log_Info("write file start filename: {}", fileName);
    //recordCalibFile();
    return fileName;
}
std::string DataRecord::initializeRecord(const std::string &filePath, const std::string &eventCode, const std::string &fileType, const uint64_t &recordTime,const double &triggerTime,const double &triggerStartTime)
{
    
    m_TriggerUTCtime = triggerTime/1000.0;
    m_TriggerStartTime =triggerStartTime;
    std::string fileName = getFileName(filePath, eventCode, fileType, recordTime);
    //脱敏
    if (!(fileType == DAT_FILE_TYPE_VIDEO_TUOMIN || fileType == DAT_FILE_TYPE_JPEG_TUOMIN))
    {
#if 0 // zjs_todo;压缩性能不够； 6s生成一个dat文件进行压缩，中间变量60M可以压成20M,用时30s。视频文件200M压成还是200M,用时23s。
        fileName += ".gz";
        // 初始化记录文件
        spRecord = std::make_shared<CRecord>(fileName, true);
#endif
        spRecord = std::make_shared<CRecord>(fileName, false);
    }
    else
    {
        spRecord = std::make_shared<CRecord>(fileName);
    }

    spRecord->Init();
    m_fileName = fileName;
    Log_Info("write file start filename: {}", fileName);
    //recordCalibFile();
    return fileName;
}

void DataRecord::recordCalibFile()
{
    //写标定参数
    //前视标定
    int i=1;
    std::string fcCalibTopicName="";
    
    for (auto &data : global_data::g_fc_calib)
    {
        std::string tmpFileName = DcAdr::Util::stringReplace(data.first, ".", "_");
        fcCalibTopicName="sda-calib_file-string-fc-"+tmpFileName;
        // Log_Info("m_firstFrameUTCtime:{},fcCalibTopicName:{}",m_firstFrameUTCtime,fcCalibTopicName);
        std::string dataStr="";
        GenerateMessage(data.first,dataStr,data.second);
        caviz::RawData rawData(fcCalibTopicName, m_FirstFrameUTCTime, dataStr);
        spRecord->Record(rawData.rawData());
        i++;
    }
    //环视标定
    
    std::string scCalibTopicName="";
    for (auto &data : global_data::g_sc_calib)
    {
        std::string tmpFileName = DcAdr::Util::stringReplace(data.first, ".", "_");
        scCalibTopicName="sda-calib_file-string-sc-"+tmpFileName;
        // Log_Info("m_firstFrameUTCtime:{},scCalibTopicName:{}",m_firstFrameUTCtime,scCalibTopicName);
        std::string dataStr="";
        GenerateMessage(data.first,dataStr,data.second);
        caviz::RawData rawData(scCalibTopicName, m_FirstFrameUTCTime, dataStr);
        spRecord->Record(rawData.rawData());
        i++;
    }
    //雷达标定
    
    std::string ldrCalibTopicName="";
    for (auto &data : global_data::g_ldr_calib)
    {
        std::string tmpFileName = DcAdr::Util::stringReplace(data.first, ".", "_");
        ldrCalibTopicName="sda-calib_file-string-ldr-"+tmpFileName;
        // Log_Info("m_firstFrameUTCtime:{},ldrCalibTopicName:{}",m_firstFrameUTCtime,ldrCalibTopicName);
        std::string dataStr="";
        GenerateMessage(data.first,dataStr,data.second);
        caviz::RawData rawData(ldrCalibTopicName, m_FirstFrameUTCTime, dataStr);
        spRecord->Record(rawData.rawData());
        i++;
                
    }
    return;
}
void DataRecord::GenerateMessage(std::string file_name, std::string &message,std::string calibData)
{
    /*
        message 格式
        uint64_t file_name_len 标定文件文件名长度
        const char* file_name 标定文件，文件名
        unint64_t data_len 标定文件内容长度
        const char* raw_data 标定文件内容
    */
    const size_t message_bytes = 16 + file_name.length() + calibData.length();
    message.resize(message_bytes);
    size_t copy_size = 0;
    // 文件名长度
    uint64_t len = file_name.length();
    (void)memcpy(&message[copy_size], &len, sizeof(len));
    copy_size += sizeof(len);
    //文件名
    (void)memcpy(&message[copy_size], &file_name[0], len);
    copy_size += len;
    //数据长度
    len = calibData.length();
    (void)memcpy(&message[copy_size], &len, sizeof(len));
    copy_size += sizeof(len);
    //数据
    (void)memcpy(&message[copy_size], &calibData[0], len);
    copy_size += len;
    return;
}

void DataRecord::record(const std::string &topicName, const double &timeStamp, const std::string &dataStr)
{
    string taskName = "sda-";
    if (m_isfirstFrame)
    {
        //m_firstFrameBaseTime = timeStamp; // 保存第一帧的capilot时间作为基础时间
        m_FirstFrameUTCTime=m_TriggerUTCtime+timeStamp-m_TriggerStartTime;//获取第一帧的utc时间，第一帧的utc时间也是标定文件的写入的时间
        Log_Info("m_FirstFrameUTCTime:{},m_TriggerUTCtime:{},timeStamp:{},m_TriggerStartTime:{}",m_FirstFrameUTCTime,m_TriggerUTCtime,timeStamp,m_TriggerStartTime);
        recordCalibFile();//先写标定文件，再写第一帧数据，时间戳是一样的
        m_isfirstFrame = false;
    }
    //double utctimeStamp = timeStamp - m_firstFrameBaseTime + m_firstFrameUTCtime;
    double utctimeStamp=m_TriggerUTCtime+timeStamp-m_TriggerStartTime;
    
    //caviz::RawData rawData(taskName + topicName, utctimeStamp, dataStr);
    //spRecord->Record(rawData.rawData());

    std::string header;
    caviz::RawData::GetRawDataHeader(header, taskName + topicName, utctimeStamp, dataStr);
    spRecord->Record(header);
    spRecord->Record(dataStr);
}

std::string DataRecord::getFileName(const std::string &filePath, const std::string &eventCode, const std::string &fileType, const uint64_t &recordTime)
{
    int ret = access(filePath.c_str(), F_OK);
    if (0 != ret)
    {
        int ret2 = mkdir(filePath.c_str(), S_IRWXU);
        (void)ret2;
    }
    //构造文件名
    std::string suffix = ".dat";
    std::string fileName = filePath;
    if (fileName.size() - (fileName.find_last_of('/') + 1) > 0) //防止记录数据时，不填写vimstr，导致记录的文件多一个下划线_
    {
        fileName += '_';
    }
    
    fileName = fileName + '1' + CommonOprTime::getDateUTC8str(recordTime) + fileType + '0' + eventCode + suffix;//控制器编码“1” + 时间 + 文件类型 + 文件子个数“0”  + 事件编码
    
    static bool oncein = false;
    if (!oncein)
    {
        oncein = true;
        string tmp = '1' + CommonOprTime::getDateUTC8str(recordTime) + fileType + '0';
        m_eventPrefixLenPos = tmp.size();
        Log_Info("m_eventPrefixLenPos:{}", m_eventPrefixLenPos);
    }

    return fileName;
}

std::string DataRecord::getFileNameType(const std::string &topic)
{
    if (VedioColSet.find(topic) != VedioColSet.end())
    {
        /**
         * @brief 视频
         * @note 所有视频存一个文件
         */
        return DAT_FILE_TYPE_VIDEO;
    }
    else if (PicColSet.find(topic) != PicColSet.end())
    {
        /**
         * @brief 图片
         * @note 所有图片存一个文件
         */
        return DAT_FILE_TYPE_JPEG;
    }
    else
    {
        /**
         * @brief 中间变量
         * @note 所有中间变量存一个文件
         */
        return DAT_FILE_TYPE_MID;
    }
}

//12024042315020820BA015.dat ->  BA015
std::string DataRecord::getEvtFromDat(const string &datName)
{
    string tmpFileName = "IT031";//IACC功能激活	IT031

    int32_t endPos = datName.find_last_of(".");
    if (endPos == std::string::npos)
    {
        return tmpFileName;
    }

    Log_Info("getevent from datFile; endPos: {} m_eventPrefixLenPos:{}", endPos, m_eventPrefixLenPos);

    // 判断substr的pos是否小于等于字符串的size
    if ((endPos - m_eventPrefixLenPos) > 0 && m_eventPrefixLenPos <= datName.size())
    {
        tmpFileName = datName.substr(m_eventPrefixLenPos, endPos - m_eventPrefixLenPos);
    }

    Log_Info("datName: {} eventname:{}", datName, tmpFileName);
    return tmpFileName;
}

//12024051414432220BA015.dat -> 12024051414432240BA015.dat 改成4类型命名   // 2024-05-16_13-46-17_2_BA009.dat
bool DataRecord::convertDesensFiletype(const std::string &fileName, std::string &desensFileName)
{
    bool ret = false;

    if (fileName.size() > 17)
    {
        desensFileName =  fileName.substr(0, 15) + DAT_FILE_TYPE_VIDEO_TUOMIN + fileName.substr(16);
        Log_Info("convert tuomin filename: {}", desensFileName);
        ret = true;
    }
    else
    {
        Log_ERROR("Desens file convert faild; fileName: {} m_eventPrefixLenPos:{}", fileName, m_eventPrefixLenPos);
        desensFileName = fileName + ".tuomin";
    }

    return ret;
}